package pw.goyd.game.api;

import pw.goyd.game.constant.enumcard.CardWeight;
import pw.goyd.game.constant.enumcard.HandCardsWeight;
import pw.goyd.game.model.Card;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 牌型计算类
 *
 * @author StanWind
 */
public class CalcCards {
    /**
     * 判断入口
     *
     * @param cards 手牌
     * @return 牛
     */
    public static HandCardsWeight calcType(List<Card> cards) {
        HandCardsWeight handCardsWeight = specialDetect(cards);
        if (handCardsWeight == HandCardsWeight.Null) {
            return detectNormalAuto(cards);
        }
        return handCardsWeight;
    }

    /**
     * 自动判断牌型(普通牌型判断)
     *
     * @param handCards 手牌
     * @return 手牌类型
     */
    public static HandCardsWeight detectNormalAuto(List<Card> handCards) {
        List<Card> selectedCards = new ArrayList<>();
        selectedCards.clear();
        // N个数中取三个取3算法实现
        for (int i = 0; i < 3; i++) {
            for (int j = i + 1; j < handCards.size() - 1; j++) {
                for (int k = j + 1; k < handCards.size(); k++) {
                    if ((handCards.get(i).getPointWeight()
                            + handCards.get(j).getPointWeight() + handCards.get(k)
                            .getPointWeight()) % 10 == 0) {
                        selectedCards.add(handCards.get(i));
                        selectedCards.add(handCards.get(j));
                        selectedCards.add(handCards.get(k));
                        return detectNormal(handCards, selectedCards);
                    }
                }
            }
        }
        return HandCardsWeight.Null;
    }

    /**
     * 特殊牌型判断(五小牛/五花牛/四炸等)
     *
     * @param handCards 手牌
     * @return 手牌类型
     */
    private static HandCardsWeight specialDetect(List<Card> handCards) {
        if (detectSmall(handCards)) {
            return HandCardsWeight.Small;
        }
        if (detectStreaky(handCards)) {
            return HandCardsWeight.Streaky;
        }
        if (detectBomb(handCards)) {
            return HandCardsWeight.Bomb;
        }
        return HandCardsWeight.Null;
    }

    /**
     * 普通牌型检测
     *
     * @param handCards    手牌
     * @param selectedCard 选中牌
     * @return 手牌类型
     */
    private static HandCardsWeight detectNormal(List<Card> handCards,
                                                List<Card> selectedCard) {
        // 在所有的手牌中找出剩下未选中的两张手牌
        List<Card> card = new ArrayList<>();
        for (int i = 0; i < handCards.size(); i++) {
            if (selectedCard.get(0) != handCards.get(i)
                    && selectedCard.get(1) != handCards.get(i)
                    && selectedCard.get(2) != handCards.get(i)) {
                card.add(handCards.get(i));
            }
        }
        int point = card.get(0).getPointWeight() + card.get(1).getPointWeight();
        if (point % 10 == 0) {
            return HandCardsWeight.Ten;
        } else {
            return HandCardsWeight.values()[point % 10];
        }
    }

    /**
     * 检查牌型是否符合五小牛牌型
     *
     * @param handCards 手牌
     * @return 是否五小牛
     */
    private static boolean detectSmall(List<Card> handCards) {
        int point = 0; // 所有手牌的点数和
        for (int i = 0; i < handCards.size(); i++) {
            if (handCards.get(i).getPointWeight() < 5) {
                point += handCards.get(i).getPointWeight();
                continue;
            } else { // 如果某张手牌点数大于等于5，则返回false
                return false;
            }
        }
        // 如果所有点数加起来小于10
        return point <= 10;
    }

    /**
     * 检测是否符合五花牛牌型
     *
     * @param handCards 手牌
     * @return 是否符合
     */
    private static boolean detectStreaky(List<Card> handCards) {
        for (int i = 0; i < handCards.size(); i++) {
            if (handCards.get(i).getWeight() == CardWeight.J.ordinal()
                    || handCards.get(i).getWeight() == CardWeight.Q.ordinal()
                    || handCards.get(i).getWeight() == CardWeight.K.ordinal()) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     * 检测是否符合四炸牌型
     *
     * @param handCards 手牌
     * @return 是否符合
     */
    private static boolean detectBomb(List<Card> handCards) {
        int count = 1;
        for (int i = 0; i < handCards.size(); i++) {
            for (int j = 0; j < handCards.size(); j++) {
                if (handCards.get(i) == handCards.get(j)) {
                    continue;
                } else {
                    if (handCards.get(i).getWeight() == handCards.get(j).getWeight()) {
                        count++;
                    }
                }
            }
            if (count == 4) {
                return true;
            } else {
                count = 1;
            }
        }
        return false;
    }

    /**
     * 找出最大的牌
     */
    public static Card calcMaxCard(List<Card> cards) {
        Collections.sort(cards);
        return cards.get(cards.size() - 1);
    }

}
